package com.lang.downloader.http.task;

import com.lang.downloader.http.config.CacheFile;
import com.lang.downloader.http.exception.HttpDownloadException;
import com.lang.progress.DProgress;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Call;
import okhttp3.Response;
import okhttp3.ResponseBody;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Slf4j
public class HttpDownloadTask implements Runnable {

    private final Integer bufferSize;
    private final CacheFile cacheFile;
    private final Call call;
    private final DProgress progress;

    public HttpDownloadTask(Integer bufferSize, CacheFile cacheFile, Call call, DProgress progress) {
        this.bufferSize = bufferSize;
        this.cacheFile = cacheFile;
        this.call = call;
        this.progress = progress;
    }

    @Override
    public void run() {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        Response response = null;
        ResponseBody responseBody = null;
        Path filePath = Paths.get(cacheFile.getFilePath());
        try {
            if (Files.exists(filePath) && (!Files.isDirectory(filePath))) {
                Files.delete(filePath);
            }
            Files.createFile(filePath);
            response = call.execute();
            responseBody = response.body();
            if (responseBody == null)
                throw new HttpDownloadException(String.format("文件=%s url=%s[Range=%d-%d] 没有输出流",
                        filePath.getFileName(), cacheFile.getHttpUrl(), cacheFile.getStart(), cacheFile.getEnd()));
            inputStream = responseBody.byteStream();
            outputStream = Files.newOutputStream(filePath);
            byte[] buffer = new byte[bufferSize];
            int tag;
            while ((tag = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, tag);
                outputStream.flush();
                progress.count(tag);
            }
            cacheFile.setDone(true);
        } catch (Exception e) {
            cacheFile.setDone(false);
            writeDownloadFileFailLog(cacheFile.getFilePath() + "-error.log", e);
        } finally {
            try {
                if (outputStream != null)
                    outputStream.close();
                if (inputStream != null)
                    inputStream.close();
                if (responseBody != null)
                    responseBody.close();
                if (response != null)
                    response.close();
            } catch (IOException e) {
                log.error(String.format("关闭文件=%s 文件流失败", filePath.getFileName()), e);
            }
        }
    }

    private void writeDownloadFileFailLog(String fileLogFilePath, Throwable cause) {
        try {
            Path fileLogPath = Paths.get(fileLogFilePath);
            if (Files.exists(fileLogPath) && (!Files.isDirectory(fileLogPath)))
                Files.delete(fileLogPath);
            Files.createFile(fileLogPath);
            OutputStream outputStream = Files.newOutputStream(fileLogPath);
            PrintStream printStream = new PrintStream(outputStream, true, StandardCharsets.UTF_8.name());
            cause.printStackTrace(printStream);
        } catch (IOException e) {
            log.error(String.format("写入文件=%s错误日志失败", fileLogFilePath), e);
        }
    }

}
